import away3d.containers.*;

import com.powerfl.frm.taf.*;

private var _bindFlowTree:Object;
private var _bindFlowState:Object;
private var _bindMouse:Object;
private function bindInit():void{
	_bindFlowTree = {};
	_bindFlowState = {};
	_bindMouse = {};
}
//-----------------------------------------------------------------------------------------------------------
final public function bindKey( ...$keyflow ):void{
	orderAdd( null, function():void{
		_bindKey( $keyflow );	
	} );
}
final public function unbindKey( ...$flows ):void{
	orderAdd( null, function():void{
		_unbindKey( $flows );	
	} );
}
final public function bindKeyEach( ...$keyflow ):void{
	orderAdd( null, function():void{
		bindKeyEach_( $keyflow );	
	} );
}
final public function bindKeyEachOnce( ...$keyflow ):void{
	orderAdd( null, function():void{
		bindKeyEach_( $keyflow, true );	
	} );
}
final public function unbindKeyEach( ...$keys ):void{
	orderAdd( null, function():void{
		if( $keys[0] ){
			unbindKeyEach_( $keys );
		}else{
			_keydownEach = new Vector.<Vector.<String>>( 230, true );
		}
	} );
}
private function _bindKey( $keyflow:Array ):void{
	var i:int, j:int, key:*;
	for( j = $keyflow.length ; i < j ; i += 2 ){
		keyAddFlow( $keyflow[i], $keyflow[i+1] );
	}
}
private function _unbindKey( $flows:Array ):void{
	var key:*;
	for each( key in $flows ){
		keyRemoveFlow( key );
	}
}
private function bindKeyEach_( $keyflow:Array, $isOnce:Boolean = false ):void{
	var i:int, j:int, keyName:*, flowName:String, autoFlow:String;
	for( j = $keyflow.length ; i < j ; i += 2 ){
		keyName = $keyflow[i];
		flowName = $keyflow[i+1];
		if( $isOnce ){
			autoFlow = flowAutoKey();
			flowAdd_( autoFlow, function():void{
				unbindKeyEach_( [keyName] );
				flowRemove( autoFlow );
				flowCall( flowName );
			} );
			keyAddEachKey( keyCode( keyName ), autoFlow );
		}else{
			keyAddEachKey( keyCode( keyName ), flowName );
		}
	}
}
private function unbindKeyEach_( $keys:Array ):void{
	var key:*;
	for each( key in $keys ){
		keyRemoveEachKey( keyCode( key ), '' );
	}
}
//-----------------------------------------------------------------------------------------------------------
final public function bindDown( $tree:String, $flow:*, $noTree:Boolean = false, ...$param ):void{
	orderAdd( null, function():void{
		bindMouse( $tree, $flow, $param, $noTree, 'Down' );
	} );
}
final public function bindUp( $tree:String, $flow:*, $noTree:Boolean = false, ...$param ):void{
	orderAdd( null, function():void{
		bindMouse( $tree, $flow, $param, $noTree, 'Up' );
	} );
}
final public function bindOut( $tree:String, $flow:*, $noTree:Boolean = false, ...$param ):void{
	orderAdd( null, function():void{
		bindMouse( $tree, $flow, $param, $noTree, 'Out' );
	} );
}
final public function bindOver( $tree:String, $flow:*, $noTree:Boolean = false, ...$param ):void{
	orderAdd( null, function():void{
		bindMouse( $tree, $flow, $param, $noTree, 'Over' );
	} );
}
final public function bindRollOut( $tree:String, $flow:*, $noTree:Boolean = false, ...$param ):void{
	orderAdd( null, function():void{
		bindMouse( $tree, $flow, $param, $noTree, 'RollOut' );
	} );
}
final public function bindRollOver( $tree:String, $flow:*, $noTree:Boolean = false, ...$param ):void{
	orderAdd( null, function():void{
		bindMouse( $tree, $flow, $param, $noTree, 'RollOver' );
	} );
}
final public function bindDownOnce( $tree:String, $flow:*, $noTree:Boolean = false, ...$param ):void{
	orderAdd( null, function():void{
		bindMouse( $tree, $flow, $param, $noTree, 'Down', true );
	} );
}
final public function bindUpOnce( $tree:String, $flow:*, $noTree:Boolean = false, ...$param ):void{
	orderAdd( null, function():void{
		bindMouse( $tree, $flow, $param, $noTree, 'Up', true );
	} );
}
final public function bindOutOnce( $tree:String, $flow:*, $noTree:Boolean = false, ...$param ):void{
	orderAdd( null, function():void{
		bindMouse( $tree, $flow, $param, $noTree, 'Out', true );
	} );
}
final public function bindOverOnce( $tree:String, $flow:*, $noTree:Boolean = false, ...$param ):void{
	orderAdd( null, function():void{
		bindMouse( $tree, $flow, $param, $noTree, 'Over', true );
	} );
}
final public function bindRollOutOnce( $tree:String, $flow:*, $noTree:Boolean = false, ...$param ):void{
	orderAdd( null, function():void{
		bindMouse( $tree, $flow, $param, $noTree, 'RollOut', true );
	} );
}
final public function bindRollOverOnce( $tree:String, $flow:*, $noTree:Boolean = false, ...$param ):void{
	orderAdd( null, function():void{
		bindMouse( $tree, $flow, $param, $noTree, 'RollOver', true );
	} );
}
private function bindMouse( $tree:String, $flow:*, $param:Array, $noTree:Boolean, $event:String, $isOnce:Boolean = false ):void{
	var key:*, temp:*, i:int, j:int, listener:Function;
	if( $noTree ){}else{
		$param.unshift( $tree );
	}
	if( $flow is String ){
		$flow = flowGet( $flow );
	}
	if( $isOnce ){
		listener = function( $e:* = null ):void{
			unbindMouse( [$tree], $event );
			$flow.apply( null, $param );
		};
	}else{
		listener = function( $e:* = null ):void{
			$flow.apply( null, $param );
		};
	}
	if( SELF._bindMouse[$event] ){}else{
		SELF._bindMouse[$event] = {};
	}
	if( SELF._bindMouse[$event][$tree] ){
		unbindMouse( [$tree], $event );
	}
	SELF._bindMouse[$event][$tree] = listener;
	tdata( $tree )['addOnMouse' + $event]( listener );
	if( 'mouseEnabled' in tdata( $tree ) ){
		tdata( $tree ).mouseEnabled = true;
	}
}
final public function unbindDown( ...$trees ):void{
	orderAdd( null, function():void{
		unbindMouse( $trees, 'Down' );
	} );
}
final public function unbindUp( ...$trees ):void{
	orderAdd( null, function():void{
		unbindMouse( $trees, 'Up' );
	} );
}
final public function unbindOut( ...$trees ):void{
	orderAdd( null, function():void{
		unbindMouse( $trees, 'Out' );
	} );
}
final public function unbindOver( ...$trees ):void{
	orderAdd( null, function():void{
		unbindMouse( $trees, 'Over' );
	} );
}
final public function unbindRollOut( ...$trees ):void{
	orderAdd( null, function():void{
		unbindMouse( $trees, 'RollOut' );
	} );
}
final public function unbindRollOver( ...$trees ):void{
	orderAdd( null, function():void{
		unbindMouse( $trees, 'RollOver' );
	} );
}
final public function unbindAll( ...$trees ):void{
	orderAdd( null, function():void{
		unbindMouse( $trees, '' );
	} );
}
private function unbindMouse( $trees:Array, $event:String ):void{
	var key:*, event:*;
	if( $trees.length && $trees[0] ){
		for each( key in $trees ){
			if( $event ){
				if( SELF._bindMouse[$event] && SELF._bindMouse[$event][key] ){ 
					tdata( key )['removeOnMouse' + $event]( SELF._bindMouse[$event][key] );
					if( 'mouseEnabled' in tdata( key ) ){
						tdata( key ).mouseEnabled = false;
					}
					delete SELF._bindMouse[$event][key];
				}
			}else{
				for( event in SELF._bindMouse ){
					if( SELF._bindMouse[event] && SELF._bindMouse[event][key] ){
						tdata( key )['removeOnMouse' + event]( SELF._bindMouse[event][key] );
						if( 'mouseEnabled' in tdata( key ) ){
							tdata( key ).mouseEnabled = false;
						}
						delete SELF._bindMouse[event][key];
					}
				}
			}
		}
	}else{
		for( event in SELF._bindMouse ){
			for( key in SELF._bindMouse[event] ){ 
				tdata( key )['removeOnMouse' + event]( SELF._bindMouse[event][key] );
				if( 'mouseEnabled' in tdata( key ) ){
					tdata( key ).mouseEnabled = false;
				}
			}
			SELF._bindMouse[event] = null;
		}
	}
}
//-----------------------------------------------------------------------------------------------------------
final public function bindRenderActivate( ...$flows ):void{
	orderAdd( null, function():void{
		bindRunner( $flows, SELF._activeRender );
	} );
}
final public function bindRenderDeactivate( ...$flows ):void{
	orderAdd( null, function():void{
		bindRunner( $flows, SELF._deactiveRender );
	} );
}
final public function bindRenderFixed( ...$flows ):void{
	orderAdd( null, function():void{
		bindRunner( $flows, SELF._fixedRender );
	} );
}
final public function bindLogicActivate( ...$flows ):void{
	orderAdd( null, function():void{
		bindRunner( $flows, SELF._activeLogic );
	} );
}
final public function bindLogicDeactivate( ...$flows ):void{
	orderAdd( null, function():void{
		bindRunner( $flows, SELF._deactiveLogic );
	} );
}
final public function bindLogicFixed( ...$flows ):void{
	orderAdd( null, function():void{
		bindRunner( $flows, SELF._fixedLogic );
	} );
}
final public function bindResize( ...$flows ):void{
	orderAdd( null, function():void{
		bindRunner( $flows, SELF._resize );
	} );
}
final public function bindLeaved( ...$flows ):void{
	orderAdd( null, function():void{
		bindRunner( $flows, SELF._leaved );
	} );
}
final public function bindComeback( ...$flows ):void{
	orderAdd( null, function():void{
		bindRunner( $flows, SELF._comeback );
	} );
}
final public function bindActivate( ...$flows ):void{
	orderAdd( null, function():void{
		bindRunner( $flows, SELF._activate );
	} );
}
final public function bindDeactivate( ...$flows ):void{
	orderAdd( null, function():void{
		bindRunner( $flows, SELF._deactivate );
	} );
}
final public function unbindRenderActivate( ...$flows ):void{
	orderAdd( null, function():void{
		unbindRunner( $flows, SELF._activeRender );
	} );
}
final public function unbindRenderDeactivate( ...$flows ):void{
	orderAdd( null, function():void{
		unbindRunner( $flows, SELF._deactiveRender );
	} );
}
final public function unbindRenderFixed( ...$flows ):void{
	orderAdd( null, function():void{
		unbindRunner( $flows, SELF._fixedRender );
	} );
}
final public function unbindLogicActivate( ...$flows ):void{
	orderAdd( null, function():void{
		unbindRunner( $flows, SELF._activeLogic );
	} );
}
final public function unbindLogicDeactivate( ...$flows ):void{
	orderAdd( null, function():void{
		unbindRunner( $flows, SELF._deactiveLogic );
	} );
}
final public function unbindLogicFixed( ...$flows ):void{
	orderAdd( null, function():void{
		unbindRunner( $flows, SELF._fixedLogic );
	} );
}
final public function unbindResize( ...$flows ):void{
	orderAdd( null, function():void{
		unbindRunner( $flows, SELF._resize );
	} );
}
final public function unbindLeaved( ...$flows ):void{
	orderAdd( null, function():void{
		unbindRunner( $flows, SELF._leaved );
	} );
}
final public function unbindComeback( ...$flows ):void{
	orderAdd( null, function():void{
		unbindRunner( $flows, SELF._comeback );
	} );
}
final public function unbindActivate( ...$flows ):void{
	orderAdd( null, function():void{
		unbindRunner( $flows, SELF._activate );
	} );
}
final public function unbindDeactivate( ...$flows ):void{
	orderAdd( null, function():void{
		unbindRunner( $flows, SELF._deactivate );
	} );
}
private function bindRunner( $flows:Array, $target:Vector.<Function> ):void{
	var flow:Function, key:*;
	for each( key in $flows ){
		if( key is String ){
			flow = flowGet( key );
		}else{
			flow = key;
		}
		if( flow is Function && $target.indexOf( flow ) === -1 ){ 
			$target[$target.length] = flow;
		}
	}
}
private function unbindRunner( $flows:Array, $target:Vector.<Function> ):void{
	var flow:Function, idx:int, key:*, target:*;
	for each( key in $flows ){
		flow = flowGet( key );
		if( flow is Function ){
			if( $target ){
				idx = $target.indexOf( flow ); 
				if( idx > -1 ){ 
					$target.splice( idx, 1 );
				}
			}else{
				for( target in SELF._runners ){
					idx = target.indexOf( flow ); 
					if( idx > -1 ){ 
						target.splice( idx, 1 );
					}
				}
			}
		}
	}
}
//-----------------------------------------------------------------------------------------------------------
final internal function plugBindRunner( $flow:Function, $target:int ):void{
	var target:Vector.<Function>;
	target = SELF._runners[$target];
	if( target.indexOf( $flow ) === -1 ){ 
		target[target.length] = $flow;
	}
}
final internal function plugUnbindRunner( $flow:Function, $target:int ):void{
	var target:Vector.<Function>, idx:int;
	target = SELF._runners[$target];
	idx = target.indexOf( $flow ); 
	if( idx > -1 ){ 
		target.splice( idx, 1 );
	}
}
//-----------------------------------------------------------------------------------------------------------
final public function bindTree( $flow:String, ...$trees ):void{
	if( $trees.length ){
		orderAdd( null, function():void{
			var bind:Array, key:*;
			bind = SELF._bindFlowTree[$flow];
			if( bind ){}else{
				SELF._bindFlowTree[$flow] = [];
				bind = SELF._bindFlowTree[$flow]; 
			}
			for each( key in $trees ){
				if( bind.indexOf( key ) === -1 ){
					bind[bind.length] = key;
				}
			}
		} );
	}
}
final public function unbindTree( $flow:String, ...$trees ):void{
	orderAdd( null, function():void{
		var bind:Array, idx:int, key:*;
		bind = SELF._bindFlowTree[$flow];
		if( bind ){
			if( $trees.length ){
				for each( key in $trees ){
					idx = bind.indexOf( key );
					if( idx > -1 ){
						bind.splice( idx, 1 );
					}
				}
			}else{
				bind.length = 0;
			}
		}
	} );
}
//-----------------------------------------------------------------------------------------------------------
final public function bindState( $flow:String, ...$stateValue ):void{
	if( $stateValue.length ){
		orderAdd( null, function():void{
			bindState_( $flow, $stateValue );
		} );
	}
}
private function bindState_( $flow:String, $stateValue:Array ):void{
	var bind:Object, state:String, i:int, j:int;
	bind = SELF._bindFlowState[$flow];
	if( bind ){}else{
		SELF._bindFlowState[$flow] = {};
		bind = SELF._bindFlowState[$flow]; 
	}
	for( i = 0 , j = $stateValue.length ; i < j ; i += 2 ){
		if( i % 2 ){
		}else if( bind[$stateValue[i]] === undefined ){
			bind[$stateValue[i]] = $stateValue[i + 1];
		}
	}
}
final public function unbindState( $flow:String, ...$states ):void{
	orderAdd( null, function():void{
		var bind:Object, idx:int, key:*;
		bind = SELF._bindFlowState[$flow];
		if( bind ){
			if( $states.length ){
				for each( key in $states ){
					delete bind[key];
				}
			}else{
				SELF._bindFlowState[$flow] = null;
			}
		}
	} );
}